package org.abc.fund.service.dataSource;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.abc.fund.dto.DataSourceConfigDTO;
import org.abc.fund.entity.factorEntity.DataSourceConfig;
import org.abc.fund.repository.factorRepository.DataSourceConfigRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 数据源配置管理服务
 * 负责处理数据源配置的业务逻辑，包括CRUD操作和实体与DTO之间的转换
 */
@Service
@RequiredArgsConstructor
@Transactional
@Slf4j
public class DataSourceConfigService {

    private final DataSourceConfigRepository dataSourceConfigRepository;
    private final ObjectMapper objectMapper;

    /**
     * 创建新的数据源配置
     *
     * @param dto 数据源配置DTO
     * @return 创建后的数据源配置DTO
     */
    public DataSourceConfigDTO createDataSourceConfig(DataSourceConfigDTO dto) {
        if (dataSourceConfigRepository.existsByDataSourceName(dto.getName())) {
            throw new IllegalArgumentException("数据源名称已存在: " + dto.getName());
        }
        DataSourceConfig config = convertToEntity(dto);
        DataSourceConfig savedConfig = dataSourceConfigRepository.save(config);
        return convertToDto(savedConfig);
    }

    /**
     * 根据ID更新数据源配置
     *
     * @param id  数据源配置ID
     * @param dto 更新后的数据源配置DTO
     * @return 更新后的数据源配置DTO
     */
    public DataSourceConfigDTO updateDataSourceConfig(Long id, DataSourceConfigDTO dto) {
        DataSourceConfig existingConfig = dataSourceConfigRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("未找到ID为 " + id + " 的数据源配置"));

        // 检查更新的名称是否与其他配置冲突
        dataSourceConfigRepository.findByDataSourceName(dto.getName()).ifPresent(config -> {
            if (!config.getId().equals(id)) {
                throw new IllegalArgumentException("数据源名称已存在: " + dto.getName());
            }
        });

        // 更新字段
        existingConfig.setDataSourceName(dto.getName());
        existingConfig.setDataSourceType(DataSourceConfig.DataSourceType.valueOf(dto.getType().toUpperCase()));
        
        // 使用ObjectMapper安全地构建connectionConfig的JSON字符串
        try {
            Map<String, String> connectionDetails = Map.of(
                    "apiUrl", dto.getApiUrl() != null ? dto.getApiUrl() : "",
                    "apiKey", dto.getApiKey() != null ? dto.getApiKey() : ""
            );
            String connectionConfigJson = objectMapper.writeValueAsString(connectionDetails);
            existingConfig.setConnectionConfig(connectionConfigJson);
        } catch (Exception e) {
            log.error("构建connectionConfig JSON失败", e);
            throw new RuntimeException("构建连接配置失败", e);
        }
        
        existingConfig.setPythonScript(dto.getPythonScript());
        existingConfig.setScheduleConfig(dto.getScheduleConfig());
        existingConfig.setEnabled(dto.getEnabled());
        existingConfig.setDescription(dto.getDescription());

        DataSourceConfig updatedConfig = dataSourceConfigRepository.save(existingConfig);
        return convertToDto(updatedConfig);
    }

    /**
     * 根据ID获取数据源配置
     *
     * @param id 数据源配置ID
     * @return 数据源配置DTO
     */
    @Transactional(readOnly = true)
    public DataSourceConfigDTO getDataSourceConfigById(Long id) {
        return dataSourceConfigRepository.findById(id)
                .map(this::convertToDto)
                .orElseThrow(() -> new RuntimeException("未找到ID为 " + id + " 的数据源配置"));
    }

    /**
     * 获取所有数据源配置
     *
     * @return 所有数据源配置的DTO列表
     */
    @Transactional(readOnly = true)
    public List<DataSourceConfigDTO> getAllDataSourceConfigs() {
        return dataSourceConfigRepository.findAll().stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    /**
     * 根据ID删除数据源配置
     *
     * @param id 数据源配置ID
     */
    public void deleteDataSourceConfig(Long id) {
        if (!dataSourceConfigRepository.existsById(id)) {
            throw new RuntimeException("未找到ID为 " + id + " 的数据源配置");
        }
        dataSourceConfigRepository.deleteById(id);
    }

    // --- DTO与实体的转换方法 ---

    /**
     * 将 DataSourceConfig 实体转换为 DTO
     *
     * @param config 实体对象
     * @return DTO对象
     */
    private DataSourceConfigDTO convertToDto(DataSourceConfig config) {
        DataSourceConfigDTO dto = new DataSourceConfigDTO();
        dto.setId(config.getId());
        dto.setName(config.getDataSourceName());
        dto.setType(config.getDataSourceType().name());
        dto.setPythonScript(config.getPythonScript());
        dto.setScheduleConfig(config.getScheduleConfig());
        dto.setEnabled(config.getEnabled());
        dto.setDescription(config.getDescription());

        // 使用ObjectMapper从connectionConfig安全地解析apiUrl和apiKey
        if (config.getConnectionConfig() != null && !config.getConnectionConfig().isEmpty()) {
            try {
                Map<String, String> connectionDetails = objectMapper.readValue(
                        config.getConnectionConfig(),
                        new TypeReference<Map<String, String>>() {}
                );
                dto.setApiUrl(connectionDetails.get("apiUrl"));
                dto.setApiKey(connectionDetails.get("apiKey")); // 警告：直接暴露apiKey存在安全风险
            } catch (Exception e) {
                log.error("解析数据源ID {} 的connectionConfig失败: {}", config.getId(), config.getConnectionConfig(), e);
                // 解析失败则忽略或设置默认值
                dto.setApiUrl(null);
                dto.setApiKey(null);
            }
        }

        return dto;
    }

    /**
     * 将 DataSourceConfigDTO 转换为实体
     *
     * @param dto DTO对象
     * @return 实体对象
     */
    private DataSourceConfig convertToEntity(DataSourceConfigDTO dto) {
        DataSourceConfig config = new DataSourceConfig();
        config.setDataSourceName(dto.getName());
        config.setDataSourceType(DataSourceConfig.DataSourceType.valueOf(dto.getType().toUpperCase()));
        
        // 使用ObjectMapper安全地构建connectionConfig的JSON字符串
        try {
            Map<String, String> connectionDetails = Map.of(
                    "apiUrl", dto.getApiUrl() != null ? dto.getApiUrl() : "",
                    "apiKey", dto.getApiKey() != null ? dto.getApiKey() : ""
            );
            String connectionConfigJson = objectMapper.writeValueAsString(connectionDetails);
            config.setConnectionConfig(connectionConfigJson);
        } catch (Exception e) {
            log.error("构建connectionConfig JSON失败", e);
            throw new RuntimeException("构建连接配置失败", e);
        }
        
        config.setPythonScript(dto.getPythonScript());
        config.setScheduleConfig(dto.getScheduleConfig());
        config.setEnabled(dto.getEnabled());
        config.setDescription(dto.getDescription());
        return config;
    }
}

